#pragma once
#include <iostream>
#include <string>
#include <queue>
#include <pthread.h>

const static int N = 5;
template <typename T>
class BlockQueue
{
private:
    bool IsFull()
    {
        return _block_queue.size() == _MaxCap;
    }

public:
    BlockQueue(int maxcap = N) : _MaxCap(maxcap)
    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_ProdCond,nullptr);
        pthread_cond_init(&_ConsumCond,nullptr);
        _low_water = _MaxCap / 2 - 1;
        _high_water = _MaxCap / 2 + 1;
    }
    void pop(T *OutData)
    {
        pthread_mutex_lock(&_mutex);
        
        while (_block_queue.empty())
        {
            pthread_cond_wait(&_ConsumCond, &_mutex);
        }
        *OutData = _block_queue.front();
        _block_queue.pop();
        /*--通知生产者--*/
        if(_block_queue.size() <= _low_water)
        {
            pthread_cond_signal(&_ProdCond);
        }
        pthread_mutex_unlock(&_mutex);
    }
    void push(const T &InData)
    {
        pthread_mutex_lock(&_mutex);
        /*--如果阻塞队列数据满了,就阻塞接口--*/
        while (IsFull())//保证代码健壮性，使用while
        {
            pthread_cond_wait(&_ProdCond, &_mutex);
        }
        /*--生产数据--*/
        _block_queue.push(InData);
        /*--通知消费者--*/
        if(_block_queue.size() >= _high_water)
        {
            pthread_cond_signal(&_ConsumCond);   
        }
        pthread_mutex_unlock(&_mutex);
    }
    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_ProdCond);
        pthread_cond_destroy(&_ConsumCond);
        _MaxCap = 0;
    }
private:
    std::queue<T> _block_queue; // 临界资源
    int _MaxCap;                // 最大容量
    pthread_mutex_t _mutex;     // 互斥锁
    pthread_cond_t _ProdCond;   // 生产者条件变量
    pthread_cond_t _ConsumCond; // 消费者条件变量
    int _low_water;
    int _high_water;
};